pub trait FromData: Sized {
	const SIZE: usize;
	fn parse(data: &[u8]) -> Option<Self>;
}
impl FromData for () {
	const SIZE: usize = 0;
	#[inline]
	fn parse(_: &[u8]) -> Option<Self> {
		Some(())
	}
}
impl FromData for u8 {
	const SIZE: usize = 1;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.get(0).copied()
	}
}
impl FromData for i8 {
	const SIZE: usize = 1;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.get(0).copied().map(|n| n as i8)
	}
}
impl FromData for u16 {
	const SIZE: usize = 2;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(u16::from_be_bytes)
	}
}
impl FromData for i16 {
	const SIZE: usize = 2;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(i16::from_be_bytes)
	}
}
impl FromData for u32 {
	const SIZE: usize = 4;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(u32::from_be_bytes)
	}
}
impl FromData for i32 {
	const SIZE: usize = 4;

	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(i32::from_be_bytes)
	}
}
impl FromData for u64 {
	const SIZE: usize = 8;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(u64::from_be_bytes)
	}
}
impl FromData for i64 {
	const SIZE: usize = 8;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(i64::from_be_bytes)
	}
}
impl FromData for f32 {
	const SIZE: usize = 4;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(f32::from_be_bytes)
	}
}
impl FromData for f64 {
	const SIZE: usize = 8;
	#[inline]
	fn parse(data: &[u8]) -> Option<Self> {
		data.try_into().ok().map(f64::from_be_bytes)
	}
}

/// A streaming binary parser.
#[derive(Clone, Default, Debug)]
pub struct Stream<'a> {
	data: &'a [u8],
	offset: usize,
}

impl<'a> Stream<'a> {
	/// Creates a new `Stream` parser.
	#[inline]
	pub fn new(data: &'a [u8]) -> Self {
		Stream { data, offset: 0 }
	}

	/// Creates a new `Stream` parser at offset.
	///
	/// Returns `None` when `offset` is out of bounds.
	#[inline]
	pub fn new_at(data: &'a [u8], offset: usize) -> Option<Self> {
		if offset <= data.len() {
			Some(Stream { data, offset })
		} else {
			None
		}
	}

	/// Checks that stream reached the end of the data.
	#[inline]
	pub fn at_end(&self) -> bool {
		self.offset >= self.data.len()
	}

	/// Jumps to the end of the stream.
	///
	/// Useful to indicate that we parsed all the data.
	#[inline]
	pub fn jump_to_end(&mut self) {
		self.offset = self.data.len();
	}

	/// Returns the current offset.
	#[inline]
	pub fn offset(&self) -> usize {
		self.offset
	}

	/// Returns the trailing data.
	///
	/// Returns `None` when `Stream` is reached the end.
	#[inline]
	pub fn tail(&self) -> Option<&'a [u8]> {
		self.data.get(self.offset..)
	}

	/// Advances by `FromData::SIZE`.
	///
	/// Doesn't check bounds.
	#[inline]
	pub fn skip<T: FromData>(&mut self) {
		self.advance(T::SIZE);
	}

	/// Advances by the specified `len`.
	///
	/// Doesn't check bounds.
	#[inline]
	pub fn advance(&mut self, len: usize) {
		self.offset += len;
	}

	/// Advances by the specified `len` and checks for bounds.
	#[inline]
	pub fn advance_checked(&mut self, len: usize) -> Option<()> {
		if self.offset + len <= self.data.len() {
			self.advance(len);
			Some(())
		} else {
			None
		}
	}

	/// Parses the type from the steam.
	///
	/// Returns `None` when there is not enough data left in the stream
	/// or the type parsing failed.
	#[inline]
	pub fn read<T: FromData>(&mut self) -> Option<T> {
		self.read_bytes(T::SIZE).and_then(T::parse)
	}

	/// Parses the type from the steam at offset.
	#[inline]
	pub fn read_at<T: FromData>(data: &[u8], offset: usize) -> Option<T> {
		data.get(offset..offset + T::SIZE).and_then(T::parse)
	}

	/// Reads N bytes from the stream.
	#[inline]
	pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
		let v = self.data.get(self.offset..self.offset + len)?;
		self.advance(len);
		Some(v)
	}
}

use std::{iter::Peekable, str::Chars};

pub struct Reader<'s> {
	line: usize,
	column: usize,
	offset: usize,
	content: &'s str,
	cursor: Peekable<Chars<'s>>,
}
impl<'s> Iterator for Reader<'s> {
	type Item = char;
	fn next(&mut self) -> Option<char> {
		match self.cursor.next() {
			Some(c) => {
				if c == '\n' {
					self.line += 1;
					self.column = 1;
				} else {
					self.column += 1;
				}
				self.offset += c.len_utf8();
				Some(c)
			}
			_ => None,
		}
	}
}
impl<'s> Reader<'s> {
	#[inline]
	pub fn new(content: &'s str) -> Self {
		Reader {
			line: 1,
			column: 1,
			offset: 0,
			content,
			cursor: content.chars().peekable(),
		}
	}
	#[inline]
	pub fn peek(&mut self) -> Option<char> {
		self.cursor.peek().copied()
	}
	#[inline]
	pub fn peek_many(&self) -> Chars<'s> {
		self.content[self.offset..].chars()
	}
	#[inline]
	pub fn position(&self) -> (usize, usize) {
		(self.line, self.column)
	}
	pub fn capture(&mut self, block: impl Fn(&mut Reader<'s>) -> bool) -> Option<&'s str> {
		let start = self.offset;
		block(self).then_some("")?;
		let content = self.content[start..self.offset].trim();
		(!content.is_empty()).then_some(content)
	}
	pub fn consume_if(&mut self, check: impl Fn(char) -> bool) -> bool {
		match self.peek() {
			Some(c) if check(c) => {
				self.next();
				true
			}
			_ => false,
		}
	}
	pub fn consume_while(&mut self, check: impl Fn(char) -> bool) -> bool {
		let mut consumed = false;
		while self.consume_if(&check) {
			consumed = true;
		}
		consumed
	}
	#[inline]
	pub fn consume_all(&mut self) -> bool {
		self.consume_while(|_| true)
	}
	#[inline]
	pub fn consume_any(&mut self, targets: &str) -> bool {
		self.consume_while(|c| targets.contains(c))
	}
	#[inline]
	pub fn consume_until_any(&mut self, targets: &str) -> bool {
		self.consume_while(|c| !targets.contains(c))
	}
	#[inline]
	pub fn consume_char(&mut self, target: char) -> bool {
		self.consume_if(|c| c == target)
	}
	#[inline]
	pub fn consume_until_char(&mut self, target: char) -> bool {
		self.consume_while(|c| c != target)
	}
}
